import operator
from functools import reduce

from django import forms
from django.db.models import Q
from django.db.models.constants import LOOKUP_SEP
from django_filters import filters


class MultiValueField(forms.Field):
    widget = forms.SelectMultiple


class JsonFieldFilter(filters.Filter):
    field_class = MultiValueField
    range_fields = ['time-range', 'date-range']
    # date_fields = ['date', 'time', 'datetime']
    choice_fields = ['select', 'checkbox']

    def filter(self, qs, value):
        if not value:
            return qs
        filter_list = Q()
        model_field = qs.model._meta.get_field(self.field_name)
        form_type = getattr(model_field, 'form_type')
        if form_type in self.range_fields:
            if len(value) > 1 and value[0]:
                lts = ('gte_key', 'lt_key')
                queries = [Q(**{getattr(self, lts[i]): v}) for i, v in enumerate(value)]
                filter_list.add(reduce(operator.and_, queries), Q.AND)
        # elif model_field.form_field in self.date_fields:
        elif form_type in self.choice_fields:
            queries = [Q(**{self.contains_key: v}) for v in value]
            filter_list.add(reduce(operator.or_, queries), Q.AND)
        if not filter_list:
            return super().filter(qs, value[0])
        return qs.filter(filter_list)

    @property
    def contains_key(self):
        return f'{self.field_name}{LOOKUP_SEP}contains'

    @property
    def gte_key(self):
        return f'{self.field_name}{LOOKUP_SEP}0{LOOKUP_SEP}gte'

    @property
    def lt_key(self):
        return f'{self.field_name}{LOOKUP_SEP}1{LOOKUP_SEP}lte'


class DateFilter(filters.Filter):
    field_class = MultiValueField

    def filter(self, qs, value):
        if value and len(value) > 1 and value[0]:
            qs = qs.filter(
                **{f'{self.field_name}{LOOKUP_SEP}gte': value[0], f'{self.field_name}{LOOKUP_SEP}lte': value[1]})
        return qs



